package fakes

import (
	"context"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/backend"
	"go-caipu/pkg/plugins"
	"go-caipu/pkg/plugins/backendplugin"
	"go-caipu/pkg/plugins/log"
	"sync"
)

// FakePluginInstaller  install Plugin Installer
type FakePluginInstaller struct {
	AddFunc func(ctx context.Context, pluginID, version string, opts plugins.AddOpts) error
	// RemoveFunc remove aplugin from the store
	RemoveFunc func(ctx context.Context, pluginID string) error
}

func (i *FakePluginInstaller) Add(ctx context.Context, pluginID, version string, opts plugins.AddOpts) error {
	if i.AddFunc != nil {
		return i.AddFunc(ctx, pluginID, version, opts)
	}
	return nil
}

func (i *FakePluginInstaller) Remove(ctx context.Context, pluginID string) error {
	if i.RemoveFunc != nil {
		return i.RemoveFunc(ctx, pluginID)
	}
	return nil
}

// FakeLoader loader plugin
type FakeLoader struct {
	LoadFunc   func(_ context.Context, _ plugins.PluginSource) ([]*plugins.Plugin, error)
	UnloadFunc func(_ context.Context, _ string) error
}

func (l *FakeLoader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) {
	if l.LoadFunc != nil {
		return l.LoadFunc(ctx, src)
	}
	return nil, nil
}

func (l *FakeLoader) Unload(ctx context.Context, pluginID string) error {
	if l.UnloadFunc != nil {
		return l.UnloadFunc(ctx, pluginID)
	}
	return nil
}

// FakePluginClient 客户端对象
type FakePluginClient struct {
	ID             string
	Managed        bool
	Log            log.Logger
	startCount     int
	stopCount      int
	exited         bool
	decommissioned bool
	backend.CollectMetricsHandlerFunc
	backend.CheckHealthHandlerFunc
	backend.QueryDataHandlerFunc
	backend.CallResourceHandlerFunc
	mutex sync.RWMutex
}

func (f FakePluginClient) PluginID() string {
	return f.ID
}

func (f FakePluginClient) Logger() log.Logger {
	return f.Log
}

func (f FakePluginClient) Start(_ context.Context) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	f.exited = false
	f.startCount++
	return nil
}

func (f FakePluginClient) Stop(_ context.Context) error {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	f.stopCount++
	f.exited = true
	return nil
}

func (f FakePluginClient) IsManaged() bool {
	return f.Managed
}

func (f FakePluginClient) Exited() bool {
	f.mutex.RLock()
	defer f.mutex.RUnlock()
	return f.exited
}

func (f FakePluginClient) Decommission() error {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	f.decommissioned = true
	return nil
}

func (f FakePluginClient) IsDecommissioned() bool {
	f.mutex.RLock()
	defer f.mutex.RUnlock()
	return f.decommissioned
}

func (f FakePluginClient) Target() backendplugin.Target {
	//TODO implement me
	panic("implement me")
}

func (f FakePluginClient) SubscribeStream(ctx context.Context, request *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
	//TODO implement me
	panic("implement me")
}

func (f FakePluginClient) PublishStream(ctx context.Context, request *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
	//TODO implement me
	panic("implement me")
}

func (f FakePluginClient) RunStream(ctx context.Context, request *backend.RunStreamRequest, sender *backend.StreamSender) error {
	//TODO implement me
	panic("implement me")
}

func (f FakePluginClient) collectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
	if f.CollectMetricsHandlerFunc != nil {
		return f.CollectMetricsHandlerFunc(ctx, req)
	}
	return nil, backendplugin.ErrMethodNotImplemented
}
func (f FakePluginClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
	if f.CheckHealthHandlerFunc != nil {
		return f.CheckHealthHandlerFunc(ctx, req)
	}

	return nil, backendplugin.ErrMethodNotImplemented
}

func (f FakePluginClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	if f.QueryDataHandlerFunc != nil {
		return f.QueryDataHandlerFunc(ctx, req)
	}

	return nil, backendplugin.ErrMethodNotImplemented
}
func (f FakePluginClient) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
	if f.CallResourceHandlerFunc != nil {
		return f.CallResourceHandlerFunc(ctx, req, sender)
	}

	return backendplugin.ErrMethodNotImplemented
}

// FakePluginRegistry 注册
type FakePluginRegistry struct {
	Store map[string]*plugins.Plugin
}

func NewFakePluginRegistry() *FakePluginRegistry {
	return &FakePluginRegistry{
		Store: make(map[string]*plugins.Plugin),
	}
}

func (f *FakePluginRegistry) Plugin(_ context.Context, id string) (*plugins.Plugin, bool) {
	p, exists := f.Store[id]
	return p, exists
}

func (f *FakePluginRegistry) Plugins(_ context.Context) []*plugins.Plugin {
	var res []*plugins.Plugin

	for _, p := range f.Store {
		res = append(res, p)
	}

	return res
}

func (f *FakePluginRegistry) Add(_ context.Context, p *plugins.Plugin) error {
	f.Store[p.ID] = p
	return nil
}

func (f *FakePluginRegistry) Remove(_ context.Context, id string) error {
	delete(f.Store, id)
	return nil
}
